package com.fingard.dsp.bank.directbank.lianlianpay01;

import com.alibaba.fastjson.JSONObject;
import com.fingard.FGBiz;
import com.fingard.dsp.bank.directbank.DirectBase;
import com.fingard.net.WebRequest;
import com.fingard.text.StringHelper;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang3.StringUtils;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.security.*;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

/**
 * 连连平台接口公共方法类
 */
public class LianLianPay01Base extends DirectBase {

    protected static String transDownloadFile = FGBiz.dspCenter.dspSet.dataDirPath + File.separator + "tempfile" + File.separator + "LianLianPay01" + File.separator;

    static {
        //Security.addProvider(new BouncyCastleProvider());
        //增加加密提供者
        Security.insertProviderAt(new BouncyCastleProvider(),1);
    }

    /**
     * 解除秘钥长度限制:
     * 1、通过反射移除了isRestricted 的变量修饰符：final
     * 2、然后将isRestricted 赋值为false
     */
    static {
        try {
            Class<?> clazz = Class.forName("javax.crypto.JceSecurity");
            Field nameField = clazz.getDeclaredField("isRestricted");

            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(nameField, nameField.getModifiers() & ~Modifier.FINAL);

            nameField.setAccessible(true);
            nameField.set(null, java.lang.Boolean.FALSE);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    /**
     * 获取字符编码
     *
     * @return 配置文件字符编码
     */
    protected String getCharset() {
        return getBankConfig().getCharset("UTF-8");
    }

    protected String[] sendToBank(String p_reqStr,String transType,String commandCode) throws Exception {
        String[] retStrArr = new String[]{"", ""};
        //后置挡板
        if(StringHelper.hasAnyChar(transType) && StringHelper.hasAnyChar(commandCode)) {
            this.detailSimulateForBank(bankFront.bankCode, transType, commandCode, p_reqStr, retStrArr);
            if (retStrArr[1].length() > 0) {
                return retStrArr;
            }
        }
        String urlType="";
        if("1908".equals(transType)){
            urlType="/paymentapi/payment.htm";
        }else if("1944".equals(transType)){
            urlType="/paymentapi/queryPayment.htm";
        }
        String serverURL = StringHelper.trimEndFileSp(bankFront.serverURL) +urlType;
        WriteBankLogLn("1.提交银行的地址：" + serverURL);
        WriteBankLogStep2(p_reqStr);
        WebRequest tmpWebRequest = new WebRequest(serverURL);
        tmpWebRequest.setConnectTimeout(60000);
        tmpWebRequest.setRequestProperty("Content-Type", "application/json;charset=utf-8");
        tmpWebRequest.setRequestProperty("connection", "Close");
        byte[] tmpToWriteBytes = p_reqStr.getBytes(getCharset());
        retStrArr = tmpWebRequest.upload(tmpToWriteBytes, getCharset());
        WriteBankLogStep3(retStrArr[1]);
        return retStrArr;
    }

    /**
     * 签名
     * @param reqObj
     * @return
     */
    protected String genRSASign(JSONObject reqObj) {
        // 生成待签名串
        String sign_src = genSignData(reqObj);
        WriteBankLogLn("商户[" + reqObj.getString("oid_partner") + "]待签名原串：" + sign_src);
        return signByPriKey(getBankConfig().getValueAsString("businessPrivateKey"), sign_src);
    }

    /**
     * 用银通公钥对请求参数json字符串加密
     * @param plaintext json字符串
     * @param public_key 银通公钥
     * @return
     * @throws Exception
     */
    protected static String encryptByBankPublicKey(String plaintext, String public_key) throws Exception {
        String hmack_key = genLetterDigitRandom(32);
        String version = "lianpay1_0_1";
        String aes_key = genLetterDigitRandom(32);
        String nonce = genLetterDigitRandom(8);
        return lianlianpayEncrypt(plaintext, public_key, hmack_key, version, aes_key, nonce);
    }


    private static String lianlianpayEncrypt(String req, String public_key, String hmack_key, String version, String aes_key, String nonce) {
        try {
            BASE64Encoder encoder = new BASE64Encoder();
            String B64hmack_key = rsaEncrypt(hmack_key, public_key);
            String B64aes_key = rsaEncrypt(aes_key, public_key);
            String B64nonce = encoder.encode(nonce.getBytes());
            String encry = aesEncrypt(req.getBytes("UTF-8"), aes_key.getBytes(), nonce.getBytes());
            String message = B64nonce + "$" + encry;
            byte[] sign = encodeHmacSHA256(message.getBytes(), hmack_key.getBytes());
            String B64sign = encoder.encode(sign);
            String encrpt_str = version + "$" + B64hmack_key + "$" + B64aes_key + "$" + B64nonce + "$" + encry + "$" + B64sign;
            return encrpt_str;
        } catch (Exception var15) {
            var15.printStackTrace();
            return null;
        }
    }

    private static String rsaEncrypt(String source, String public_key) throws Exception {
        BASE64Decoder b64d = new BASE64Decoder();
        byte[] keyByte = b64d.decodeBuffer(public_key);
        X509EncodedKeySpec x509ek = new X509EncodedKeySpec(keyByte);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(x509ek);
        Cipher cipher = Cipher.getInstance("RSA/ECB/OAEPWithSHA1AndMGF1Padding");
        cipher.init(1, publicKey);
        byte[] sbt = source.getBytes("UTF-8");
        byte[] epByte = cipher.doFinal(sbt);
        BASE64Encoder encoder = new BASE64Encoder();
        String epStr = encoder.encode(epByte);
        return epStr;
    }

    private static String aesEncrypt(byte[] msgbt, byte[] aesKey, byte[] nonce) throws Exception {
        SecretKeySpec secretKeySpec = new SecretKeySpec(aesKey, "AES");
        Cipher cipher = Cipher.getInstance("AES/CTR/NoPadding");
        IvParameterSpec ips = createCtrIv(nonce);
        cipher.init(1, secretKeySpec, ips);
        byte[] epByte = cipher.doFinal(msgbt);
        BASE64Encoder encoder = new BASE64Encoder();
        String epStr = encoder.encode(epByte);
        return epStr;
    }

    private static byte[] encodeHmacSHA256(byte[] data, byte[] key) throws Exception {
        SecretKey secretKey = new SecretKeySpec(key, "HmacSHA256");
        Mac mac = Mac.getInstance(secretKey.getAlgorithm());
        mac.init(secretKey);
        byte[] digest = mac.doFinal(data);
        return digest;
    }

    private static String genLetterDigitRandom(int size) {
        StringBuffer allLetterDigit = new StringBuffer("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ");
        Random random = new Random();
        StringBuffer randomSb = new StringBuffer("");

        for(int i = 0; i < size; ++i) {
            randomSb.append(allLetterDigit.charAt(random.nextInt(allLetterDigit.length())));
        }

        return randomSb.toString();
    }

    private static IvParameterSpec createCtrIv(byte[] nonce) {
        byte[] counter = new byte[]{0, 0, 0, 0, 0, 0, 0, 1};
        byte[] output = new byte[nonce.length + counter.length];

        int i;
        for(i = 0; i < nonce.length; ++i) {
            output[i] = nonce[i];
        }

        for(i = 0; i < counter.length; ++i) {
            output[i + nonce.length] = counter[i];
        }

        return new IvParameterSpec(output);
    }

    /**
     * 生成待签名串
     *
     * @param jsonObject
     * @return
     */
    protected static String genSignData(JSONObject jsonObject) {
        StringBuffer content = new StringBuffer();

        // 按照key做首字母升序排列
        List<String> keys = new ArrayList<String>(jsonObject.keySet());
        Collections.sort(keys, String.CASE_INSENSITIVE_ORDER);
        for (int i = 0; i < keys.size(); i++) {
            String key = (String) keys.get(i);
            // sign 和ip_client 不参与签名
            if ("sign".equals(key)) {
                continue;
            }
            String value = (String) jsonObject.getString(key);
            // 空串不参与签名
            if (StringUtils.isEmpty(value)) {
                continue;
            }
            content.append((i == 0 ? "" : "&") + key + "=" + value);

        }
        String signSrc = content.toString();
        if (signSrc.startsWith("&")) {
            signSrc = signSrc.replaceFirst("&", "");
        }
        return signSrc;
    }

    /**
     * 签名验证
     * @param pubkeyvalue
     * @param oid_str
     * @param signed_str
     * @return
     */
    protected static boolean checkSignByPubKey(String pubkeyvalue, String oid_str, String signed_str) {
        try {
            X509EncodedKeySpec bobPubKeySpec = new X509EncodedKeySpec(Base64.decodeBase64(pubkeyvalue.getBytes("UTF-8")));
            KeyFactory keyFactory = KeyFactory.getInstance("RSA");
            PublicKey pubKey = keyFactory.generatePublic(bobPubKeySpec);
            byte[] signed = Base64.decodeBase64(signed_str.getBytes());
            Signature signetcheck = Signature.getInstance("MD5withRSA");
            signetcheck.initVerify(pubKey);
            signetcheck.update(oid_str.getBytes("UTF-8"));
            return signetcheck.verify(signed);
        } catch (Exception var8) {
            return false;
        }
    }

    /**
     * 签名
     * @param prikeyvalue 商户私钥
     * @param sign_str 签名原文
     * @return
     */
    private static String signByPriKey(String prikeyvalue, String sign_str) {
        try {
            PKCS8EncodedKeySpec priPKCS8 = new PKCS8EncodedKeySpec(Base64.decodeBase64(prikeyvalue.getBytes("UTF-8")));
            KeyFactory keyf = KeyFactory.getInstance("RSA");
            PrivateKey myprikey = keyf.generatePrivate(priPKCS8);
            Signature signet = Signature.getInstance("MD5withRSA");
            signet.initSign(myprikey);
            signet.update(sign_str.getBytes("UTF-8"));
            byte[] signed = signet.sign();
            return new String(Base64.encodeBase64(signed));
        } catch (Exception var7) {
            return null;
        }
    }

    /**
     * 获取数组的值
     * @param eachNode
     * @param index
     * @return
     */
    protected String getValueByIndex(String[] eachNode,Integer index){
        String result="";
        if(eachNode.length>index){
            result=eachNode[index];
        }
        return result;
    }
}
